package net.p2pcdn.pay.paypal;

import com.alibaba.fastjson.JSON;
import com.paypal.api.payments.*;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import net.p2pcdn.common.PayPalAccessTokenProvider;
import net.p2pcdn.core.order.domain.Contract;
import net.p2pcdn.core.order.domain.Order;
import net.p2pcdn.core.order.domain.PayType;
import net.p2pcdn.core.order.domain.PlatformEnum;
import net.p2pcdn.core.order.service.ContractService;
import net.p2pcdn.core.order.service.OrderService;
import net.p2pcdn.core.product.domain.ProductType;
import net.p2pcdn.core.product.repository.VirtualItemRepository;
import net.p2pcdn.pay.OrderGenerator;
import net.p2pcdn.pay.OrderGeneratorFactory;
import net.p2pcdn.pay.paypal.config.CreatePaymentCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Service
public class BalanceOrderGenerator implements OrderGenerator {
    @Resource
    private VirtualItemRepository virtualItemRepository;
    @Autowired
    private PayPalAccessTokenProvider payPalAccessTokenProvider;
    @Autowired
    private OrderGeneratorFactory orderGeneratorFactory;
    @Autowired
    private OrderService orderService;
    @Autowired
    private APIContext apiContext;
    @Value("${paypal.mode}")
    private String mode;
    @Autowired
    private ContractService contractService;

    public APIContext getApiContext() {
        return apiContext;
    }

    @Override
    @Transactional(rollbackFor = {PayPalRESTException.class, RuntimeException.class})
    public Payment createPayment(CreatePaymentCommand command) throws PayPalRESTException {
        Contract contract = contractService.getById(command.getContractId());
        if(contract.getExpireTime().compareTo(new Date()) < 0){
            throw new RuntimeException("此服务已过期，不能充值流量");
        }
        Amount amount = new Amount();
        amount.setCurrency(command.getCurrency());
        amount.setTotal(new BigDecimal(command.getAmountOfMoney()).setScale(2, RoundingMode.HALF_UP).toString());
        Order addChargeOrder = orderService.addChargeOrder(command.getUserId(), command.getUserId(), new BigDecimal(amount.getTotal()), PayType.ONLINE, PlatformEnum.PAYPAL);

        Transaction transaction = new Transaction();
        transaction.setDescription("P2PCDN-余额充值,充值金额：" + amount.getTotal());
        transaction.setAmount(amount);
        transaction.setNotifyUrl(command.getNotifyUrl());
        transaction.setCustom(generatorCallbackParameterJSONString(command.getUserId(), amount.getTotal(), addChargeOrder.getTradeNo()));

        List<Transaction> transactions = new ArrayList<>();
        transactions.add(transaction);

        Payer payer = new Payer();
        payer.setPaymentMethod(command.getPaymentMethod().toString());

        Payment payment = new Payment();
        payment.setIntent(command.getPaypalPaymentIntent().toString());
        payment.setPayer(payer);
        payment.setTransactions(transactions);
        RedirectUrls redirectUrls = new RedirectUrls();
        redirectUrls.setCancelUrl(command.getCancelUrl() + "?tradeNo=" + addChargeOrder.getTradeNo());
        redirectUrls.setReturnUrl(command.getSuccessUrl() + "?tradeNo=" + addChargeOrder.getTradeNo());
        payment.setRedirectUrls(redirectUrls);
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Basic " + payPalAccessTokenProvider.getAccessToken());
        APIContext context = new APIContext(getApiContext().getClientID(), getApiContext().getClientSecret(), mode);
        context.setHTTPHeaders(header);
        return payment.create(context);
    }

    @Override
    public ProductType getProductType() {
        return ProductType.BALANCE;
    }

    public String generatorCallbackParameterJSONString(int userId, String amountOfMoney, String orderNo) {
        Map<String, Object> params = new HashMap<>(8);
        params.put("buyer", userId);
        params.put("productType", getProductType().getValue());
        params.put("amountOfMoney", amountOfMoney);
        params.put("orderNo", orderNo);
        return JSON.toJSONString(params);
    }

    @Override
    public void afterPropertiesSet() {
        orderGeneratorFactory.addGenerator(getProductType(), this);
    }

}
